home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 97 / CD-ROM 97 / CD-ROM 97.iso / internet / ghostzilla / ghsetup.exe / chrome / comm.jar / content / navigator / metadata.js < prev    next >
Encoding:
Text File  |  2002-04-10  |  16.0 KB  |  534 lines

  1. /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  *
  13.  * The Original Code is this file as it was released on
  14.  * January 3, 2001.
  15.  *
  16.  * The Initial Developer of the Original Code is Jonas Sicking.
  17.  * Portions created by Jonas Sicking are Copyright (C) 2000
  18.  * Jonas Sicking.  All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Jonas Sicking <sicking@bigfoot.com> (Original Author)
  22.  *   Gervase Markham <gerv@gerv.net>
  23.  *   Heikki Toivonen <heikki@netscape.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the
  26.  * terms of the GNU General Public License Version 2 or later (the
  27.  * "GPL"), in which case the provisions of the GPL are applicable
  28.  * instead of those above.  If you wish to allow use of your
  29.  * version of this file only under the terms of the GPL and not to
  30.  * allow others to use your version of this file under the MPL,
  31.  * indicate your decision by deleting the provisions above and
  32.  * replace them with the notice and other provisions required by
  33.  * the GPL.  If you do not delete the provisions above, a recipient
  34.  * may use your version of this file under either the MPL or the
  35.  * GPL.
  36.  *
  37.  */
  38.  
  39. const XLinkNS = "http://www.w3.org/1999/xlink";
  40. const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  41. const XMLNS = "http://www.w3.org/XML/1998/namespace";
  42. const XHTMLNS = "http://www.w3.org/1999/xhtml";
  43. var gMetadataBundle;
  44. var gLangBundle;
  45. var gRegionBundle;
  46. var nodeView;
  47. var htmlMode = false;
  48.  
  49. var onLink   = false;
  50. var onImage  = false;
  51. var onInsDel = false;
  52. var onQuote  = false;
  53. var onMisc   = false;
  54. var onTable  = false;
  55. var onTitle  = false;
  56. var onLang   = false;
  57.  
  58. function onLoad()
  59. {
  60.     gMetadataBundle = document.getElementById("bundle_metadata");
  61.     gLangBundle = document.getElementById("bundle_languages");
  62.     gRegionBundle = document.getElementById("bundle_regions");
  63.     
  64.     showMetadataFor(window.arguments[0]);
  65.  
  66.     nodeView = window.arguments[0].ownerDocument.defaultView;
  67. }
  68.  
  69. function showMetadataFor(elem)
  70. {
  71.     // skip past non-element nodes
  72.     while (elem && elem.nodeType != Node.ELEMENT_NODE)
  73.         elem = elem.parentNode;
  74.  
  75.     if (!elem) {
  76.         alert(gMetadataBundle.getString("unableToShowProps"));
  77.         window.close();
  78.     }
  79.  
  80.     if (elem.ownerDocument.getElementsByName && !elem.ownerDocument.namespaceURI)
  81.         htmlMode = true;
  82.     
  83.     // htmllocalname is "" if it's not an html tag, or the name of the tag if it is.
  84.     var htmllocalname = "";
  85.     if (isHTMLElement(elem,"")) { 
  86.         htmllocalname = elem.localName.toLowerCase();
  87.     }
  88.     
  89.     // We only look for images once
  90.     checkForImage(elem, htmllocalname);
  91.     
  92.     // Walk up the tree, looking for elements of interest.
  93.     // Each of them could be at a different level in the tree, so they each
  94.     // need their own boolean to tell us to stop looking.
  95.     while (elem && elem.nodeType == Node.ELEMENT_NODE) {
  96.         if (!onLink)   checkForLink(elem, htmllocalname);
  97.         if (!onInsDel) checkForInsDel(elem, htmllocalname);
  98.         if (!onQuote)  checkForQuote(elem, htmllocalname);
  99.         if (!onTable)  checkForTable(elem, htmllocalname);
  100.         if (!onTitle)  checkForTitle(elem, htmllocalname);
  101.         if (!onLang)   checkForLang(elem, htmllocalname);
  102.           
  103.         elem = elem.parentNode;
  104.  
  105.         htmllocalname = "";
  106.         if (isHTMLElement(elem,"")) { 
  107.             htmllocalname = elem.localName.toLowerCase();
  108.         }
  109.     }
  110.     
  111.     // Decide which sections to show
  112.     var onMisc = onTable || onTitle || onLang;
  113.     if (!onMisc)   hideNode("misc-sec");
  114.     if (!onLink)   hideNode("link-sec");
  115.     if (!onImage)  hideNode("image-sec");
  116.     if (!onInsDel) hideNode("insdel-sec");
  117.     if (!onQuote)  hideNode("quote-sec");
  118.  
  119.     // Fix the Misc section visibilities
  120.     if (onMisc) {
  121.         if (!onTable) hideNode("misc-tblsummary");
  122.         if (!onLang)  hideNode("misc-lang");
  123.         if (!onTitle) hideNode("misc-title");
  124.     }
  125.  
  126.     // Get rid of the "No properties" message. This is a backstop -
  127.     // it should really never show, as long as nsContextMenu.js's
  128.     // checking doesn't get broken.
  129.     if (onLink || onImage || onInsDel || onQuote || onMisc)
  130.         hideNode("no-properties")
  131. }
  132.  
  133.  
  134. function checkForImage(elem, htmllocalname)
  135. {
  136.     var img;
  137.     var imgType;   // "img" = <img>
  138.                    // "object" = <object>
  139.                    // "input" = <input type=image>
  140.                    // "background" = css background (to be added later)
  141.  
  142.     if (htmllocalname === "img") {
  143.         img = elem;
  144.         imgType = "img";
  145.  
  146.     } else if (htmllocalname === "object" &&
  147.                elem.type.substring(0,6) == "image/" &&
  148.                elem.data) {
  149.         img = elem;
  150.         imgType = "object";
  151.  
  152.     } else if (htmllocalname === "input" &&
  153.                elem.type.toUpperCase() == "IMAGE") {
  154.         img = elem;
  155.         imgType = "input";
  156.  
  157.     } else if (htmllocalname === "area" || htmllocalname === "a") {
  158.  
  159.         // Clicked in image map?
  160.         var map = elem;
  161.         while (map && map.nodeType == Node.ELEMENT_NODE && !isHTMLElement(map,"map") )
  162.             map = map.parentNode;
  163.  
  164.         if (map && map.nodeType == Node.ELEMENT_NODE)
  165.             img = getImageForMap(map);
  166.     }
  167.  
  168.     if (img) {
  169.         setInfo("image-url", img.src);
  170.         if ("width" in img) {
  171.             setInfo("image-width", img.width);
  172.             setInfo("image-height", img.height);
  173.         }
  174.     else {
  175.         setInfo("image-width", "");
  176.         setInfo("image-height", "");
  177.     }    
  178.      
  179.         if (imgType == "img") {
  180.             setInfo("image-desc", getAbsoluteURL(img.longDesc, img));
  181.         } else {
  182.             setInfo("image-desc", "");
  183.         }
  184.         
  185.         onImage = true;
  186.     }
  187. }
  188.  
  189. function checkForLink(elem, htmllocalname)
  190. {
  191.     if ((htmllocalname === "a" && elem.href != "") ||
  192.         htmllocalname === "area") {
  193.  
  194.         setInfo("link-lang", convertLanguageCode(elem.getAttribute("hreflang")));
  195.         setInfo("link-url",  elem.href);
  196.         setInfo("link-type", elem.getAttribute("type"));
  197.         setInfo("link-rel",  elem.getAttribute("rel"));
  198.         setInfo("link-rev",  elem.getAttribute("rev"));
  199.  
  200.         target = elem.target;
  201.  
  202.         switch (target) {
  203.         case "_top":
  204.             setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  205.             break;
  206.         case "_parent":
  207.             setInfo("link-target", gMetadataBundle.getString("parentFrameText"));
  208.             break;
  209.         case "_blank":
  210.             setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  211.             break;
  212.         case "":
  213.         case "_self":
  214.             if (elem.ownerDocument != elem.ownerDocument.defaultView._content.document)
  215.                 setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  216.             else
  217.                 setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  218.             break;
  219.         default:
  220.             setInfo("link-target", "\"" + target + "\"");
  221.         }
  222.         
  223.         onLink = true;
  224.     }
  225.  
  226.     else if (elem.getAttributeNS(XLinkNS,"href") != "") {
  227.         setInfo("link-url", getAbsoluteURL(elem.getAttributeNS(XLinkNS,"href"),elem));
  228.         setInfo("link-lang", "");
  229.         setInfo("link-type", "");
  230.         setInfo("link-rel", "");
  231.         setInfo("link-rev", "");
  232.  
  233.         switch (elem.getAttributeNS(XLinkNS,"show")) {
  234.         case "embed":
  235.             setInfo("link-target", gMetadataBundle.getString("embeddedText"));
  236.             break;
  237.         case "new":
  238.             setInfo("link-target", gMetadataBundle.getString("newWindowText"));
  239.             break;
  240.         case "":
  241.         case "replace":
  242.             if (elem.ownerDocument != elem.ownerDocument.defaultView._content.document)
  243.                 setInfo("link-target", gMetadataBundle.getString("sameFrameText"));
  244.             else
  245.                 setInfo("link-target", gMetadataBundle.getString("sameWindowText"));
  246.             break;
  247.         default:
  248.             setInfo("link-target", "");
  249.             break;
  250.         }
  251.         
  252.         onLink = true;
  253.     }
  254. }
  255.  
  256. function checkForInsDel(elem, htmllocalname)
  257. {
  258.     if ((htmllocalname === "ins" || htmllocalname === "del") &&
  259.         (elem.cite || elem.dateTime)) {
  260.         setInfo("insdel-cite", getAbsoluteURL(elem.cite, elem));
  261.         setInfo("insdel-date", elem.dateTime);
  262.         onInsDel = true;
  263.     } 
  264. }
  265.  
  266.  
  267. function checkForQuote(elem, htmllocalname)
  268. {
  269.     if ((htmllocalname === "q" || htmllocalname === "blockquote") && elem.cite) {
  270.         setInfo("quote-cite", getAbsoluteURL(elem.cite, elem));
  271.         onQuote = true;
  272.     } 
  273. }
  274.  
  275. function checkForTable(elem, htmllocalname)
  276. {
  277.     if (htmllocalname === "table" && elem.summary) {
  278.         setInfo("misc-tblsummary", elem.summary);
  279.         onTable = true;
  280.     }
  281. }
  282.  
  283. function checkForLang(elem, htmllocalname)
  284. {
  285.     if ((htmllocalname && elem.lang) || elem.getAttributeNS(XMLNS, "lang")) {
  286.         var abbr;
  287.         if (htmllocalname && elem.lang)
  288.             abbr = elem.lang;
  289.         else
  290.             abbr = elem.getAttributeNS(XMLNS, "lang");
  291.             
  292.         setInfo("misc-lang", convertLanguageCode(abbr));
  293.         onLang = true;
  294.     }
  295. }
  296.     
  297. function checkForTitle(elem, htmllocalname)
  298. {
  299.     if (htmllocalname && elem.title) {
  300.         setInfo("misc-title", elem.title);
  301.         onTitle = true;
  302.     }    
  303. }
  304.  
  305. /*
  306.  * Set text of node id to value
  307.  * if value="" the node with specified id is hidden.
  308.  * Node should be have one of these forms
  309.  * <xul:label id="id-text" value=""/>
  310.  * <xul:description id="id-text"/>
  311.  */
  312. function setInfo(id, value)
  313. {
  314.     if (value == "") {
  315.         hideNode(id);
  316.         return;
  317.     }
  318.  
  319.     var node = document.getElementById(id+"-text");
  320.  
  321.     if (node.namespaceURI == XULNS && node.localName == "label") {
  322.         node.setAttribute("value",value);
  323.  
  324.     } else if (node.namespaceURI == XULNS && node.localName == "description") {
  325.         while (node.hasChildNodes())
  326.             node.removeChild(node.firstChild);
  327.         node.appendChild(node.ownerDocument.createTextNode(value));
  328.     }
  329. }
  330.  
  331. // Hide node with specified id
  332. function hideNode(id)
  333. {
  334.     var style = document.getElementById(id).getAttribute("style");
  335.     document.getElementById(id).setAttribute("style", "display:none;" + style);
  336. }
  337.  
  338. const nsIScriptSecurityManager = Components.interfaces.nsIScriptSecurityManager;
  339.  
  340. // opens the link contained in the node's "value" attribute.
  341. function openLink(node)
  342. {
  343.     var url = node.getAttribute("value");
  344.     // Security-Critical: Only links to 'safe' protocols should be functional.
  345.     // Specifically, javascript: and data: URLs must be made non-functional
  346.     // here, because they will run with full privilege.
  347.     var safeurls = /(^http(s)?:|^file:|^chrome:|^resource:|^mailbox:|^imap:|^news:|^about:|^mailto:|^ftp:|^gopher:)/i;
  348.     if (url.search(safeurls) == 0) {
  349.         var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService().
  350.                          QueryInterface(nsIScriptSecurityManager);
  351.         try {
  352.             secMan.checkLoadURIStr(nodeView._content.document.location,
  353.                                    url, nsIScriptSecurityManager.STANDARD);
  354.         } catch (e) {
  355.             return;
  356.         }
  357.         nodeView._content.document.location = url;
  358.         window.close();
  359.     }
  360. }
  361.  
  362. /*
  363.  * Find <img> or <object> which uses an imagemap.
  364.  * If more then one object is found we can't determine which one
  365.  * was clicked.
  366.  *
  367.  * This code has to be changed once bug 1882 is fixed.
  368.  * Once bug 72527 is fixed this code should use the .images collection.
  369.  */
  370. function getImageForMap(map)
  371. {
  372.     var mapuri = "#" + map.getAttribute("name");
  373.     var multipleFound = false;
  374.     var img;
  375.  
  376.     var list = getHTMLElements(map.ownerDocument, "img");
  377.     for (var i=0; i < list.length; i++) {
  378.         if (list.item(i).getAttribute("usemap") == mapuri) {
  379.             if (img) {
  380.                 multipleFound = true;
  381.                 break;
  382.             } else {
  383.                 img = list.item(i);
  384.                 imgType = "img";
  385.             }
  386.         }
  387.     }
  388.  
  389.     list = getHTMLElements(map.ownerDocument, "object");
  390.     for (i = 0; i < list.length; i++) {
  391.         if (list.item(i).getAttribute("usemap") == mapuri) {
  392.             if (img) {
  393.               multipleFound = true;
  394.               break;
  395.             } else {
  396.               img = list.item(i);
  397.               imgType = "object";
  398.             }
  399.         }
  400.     }
  401.  
  402.     if (multipleFound)
  403.         img = null;
  404.  
  405.     return img;
  406. }
  407.  
  408. /*
  409.  * Takes care of XMLBase and <base>
  410.  * url is the possibly relative url.
  411.  * node is the node where the url was given (needed for XMLBase)
  412.  *
  413.  * This function is called in many places as a workaround for bug 72524
  414.  * Once bug 72522 is fixed this code should use the Node.baseURI attribute
  415.  *
  416.  * for node==null or url=="", empty string is returned
  417.  */
  418. function getAbsoluteURL(url, node)
  419. {
  420.     if (!url || !node)
  421.         return "";
  422.  
  423.     var urlArr = new Array(url);
  424.     var doc = node.ownerDocument;
  425.  
  426.     if (node.nodeType == Node.ATTRIBUTE_NODE)
  427.         node = node.ownerElement;
  428.  
  429.     while (node && node.nodeType == Node.ELEMENT_NODE) {
  430.         if (node.getAttributeNS(XMLNS, "base") != "")
  431.             urlArr.unshift(node.getAttributeNS(XMLNS, "base"));
  432.  
  433.         node = node.parentNode;
  434.     }
  435.  
  436.     // Look for a <base>.
  437.     var baseTags = getHTMLElements(doc,"base");
  438.     if (baseTags && baseTags.length) {
  439.         urlArr.unshift(baseTags[baseTags.length - 1].getAttribute("href"));
  440.     }
  441.  
  442.     // resolve everything from bottom up, starting with document location
  443.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  444.                   .getService(Components.interfaces.nsIIOService);
  445.     var URL = ioService.newURI(doc.location.href, null, null);
  446.     for (var i=0; i<urlArr.length; i++) {
  447.         URL.spec = URL.resolve(urlArr[i]);
  448.     }
  449.  
  450.     return URL.spec;
  451. }
  452.  
  453. function getHTMLElements(node, name)
  454. {
  455.     if (htmlMode)
  456.         return node.getElementsByTagName(name);
  457.     return node.getElementsByTagNameNS(XHTMLNS, name);
  458. }
  459.  
  460. // name should be in lower case
  461. function isHTMLElement(node, name)
  462. {
  463.     if (node.nodeType != Node.ELEMENT_NODE)
  464.         return false;
  465.  
  466.     if (htmlMode)
  467.         return !name || node.localName.toLowerCase() == name;
  468.  
  469.     return (!name || node.localName == name) && node.namespaceURI == XHTMLNS;
  470. }
  471.  
  472. // This function coded according to the spec at:
  473. // http://www.bath.ac.uk/~py8ieh/internet/discussion/metadata.txt
  474. function convertLanguageCode(abbr)
  475. {
  476.     if (!abbr) return "";
  477.     var result;
  478.     var tokens = abbr.split("-");
  479.  
  480.     if (tokens[0] === "x" || tokens[0] === "i")
  481.     {
  482.         // x and i prefixes mean unofficial ones. So we upper-case the first
  483.         // word and leave the rest.
  484.         tokens.shift();
  485.  
  486.         if (tokens[0])
  487.         {
  488.             // Upper-case first letter
  489.             result = tokens[0].substr(0, 1).toUpperCase() + tokens[0].substr(1);
  490.             tokens.shift();
  491.  
  492.             if (tokens[0])
  493.             {
  494.                 // Add on the rest as space-separated strings inside the brackets
  495.                 result += " (" + tokens.join(" ") + ")";
  496.             }
  497.         }
  498.     }
  499.     else
  500.     {
  501.         // Otherwise we treat the first as a lang, the second as a region
  502.         // and the rest as strings.
  503.         try
  504.         {
  505.             result = gLangBundle.getString(tokens[0]);
  506.         }
  507.         catch (e) 
  508.         {
  509.             // Language not present in lang bundle
  510.             result = tokens[0]; 
  511.         }
  512.  
  513.         tokens.shift();
  514.  
  515.         if (tokens[0])
  516.         {
  517.             try
  518.             {
  519.                 // We don't add it on to the result immediately
  520.                 // because we want to get the spacing right.
  521.                 tokens[0] = gRegionBundle.getString(tokens[0].toLowerCase());
  522.             }
  523.             catch (e) 
  524.             {
  525.                 // Region not present in region bundle
  526.             }
  527.  
  528.             result += " (" + tokens.join(" ") + ")";
  529.         }
  530.     }
  531.  
  532.     return result;
  533. }
  534.